package store

import (
	"crypto/md5"
	"encoding/hex"
	"gitee.com/moyrn/sa/store/models"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"io"
	"log"
	"os"
)

// TODO 将 Store 拆分为RPC服务, 解决 cgo 编译不便的问题
type Store struct {
	*gorm.DB
}

func NewStore(filename string) (*Store, error) {
	file, err := os.OpenFile(filename+".log", os.O_APPEND|os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		return nil, err
	}

	db, err := gorm.Open(sqlite.Open(filename), &gorm.Config{
		Logger: logger.New(log.New(io.MultiWriter(os.Stdout, file), "", log.LstdFlags), logger.Config{
			Colorful: true,
			LogLevel: logger.Warn,
		}),
	})
	if err != nil {
		return nil, err
	}

	if err := db.AutoMigrate(&models.Task{}); err != nil {
		return nil, err
	}

	return &Store{
		DB: db,
	}, nil
}

func UniqueIndex(v ...string) string {
	obj := md5.New()
	for _, vv := range v {
		obj.Write([]byte(vv))
	}
	return hex.EncodeToString(obj.Sum(nil))
}

func (s *Store) Read() (task models.Task, err error) {
	tx := s.Begin()
	if err := task.Load(tx); err != nil {
		tx.Rollback()
		return models.Task{}, err
	}
	if err := tx.Commit().Error; err != nil {
		tx.Rollback()
		return task, err
	}

	if err := s.Where("id = ?", task.ID).First(&task).Error; err != nil {
		return task, err
	}
	return task, nil
}

func (s *Store) All() []models.Task {
	var task models.Task
	return task.All(s.DB)
}

func (s *Store) Loaded2Unload() error {
	var task models.Task
	return task.Loaded2Unload(s.DB)
}

func (s *Store) SetLineFinished(taskID int, title, content, remark, failedReason string) error {
	var task models.Task
	task.ID = taskID
	return task.SetLineFinished(s.DB, map[string]interface{}{
		"status":        models.Finish,
		"title":         title,
		"content":       content,
		"remark":        remark,
		"failed_reason": failedReason,
	})
}

func (s *Store) GetUnFinished() (tasks []models.Task, err error) {
	var task models.Task
	return task.GetUnFinished(s.DB)
}

func (s *Store) Write(task *models.Task) error {
	return task.Write(s.DB)
}

func (s *Store) CountUnload() (count int64) {
	var task models.Task
	return task.CountUnload(s.DB)
}
